Skip to content

feat: add signet-rpc-storage crate with ETH RPC endpoints#75

Closed
prestwich wants to merge 40 commits intomainfrom
feat/rpc-storage-scaffolding
Closed

feat: add signet-rpc-storage crate with ETH RPC endpoints#75
prestwich wants to merge 40 commits intomainfrom
feat/rpc-storage-scaffolding

Conversation

@prestwich
Copy link
Member

@prestwich prestwich commented Feb 11, 2026

Summary

  • Adds the signet-rpc-storage crate providing Ethereum JSON-RPC endpoints backed by signet-storage (hot + cold), independent of reth's FullNodeComponents
  • StorageRpcCtx wraps UnifiedStorage, BlockTags, system constants, optional TxCache, and RPC gas cap
  • BlockTags provides atomic latest/safe/finalized block tracking with sync/async resolution
  • Implements 24 supported ETH namespace endpoints:
    • Simple queries: blockNumber, chainId
    • Block queries: getBlockByHash/Number, getBlockTransactionCount*, getBlockReceipts, getBlockHeader*
    • Transaction queries: getTransactionByHash, getRawTransactionByHash, *ByBlockAndIndex, getTransactionReceipt
    • Account state (hot storage): getBalance, getStorageAt, getTransactionCount, getCode
    • EVM execution: call, estimateGas via signet-evm/trevm
    • Transaction submission: sendRawTransaction via TxCache
    • Logs: getLogs with bloom filter matching
  • 30 unsupported methods return explicit "not supported" errors
  • Uses signet-storage 0.3.0 from crates.io

Test plan

  • cargo clippy -p signet-rpc-storage --all-features --all-targets — clean
  • cargo clippy -p signet-rpc-storage --no-default-features --all-targets — clean
  • cargo +nightly fmt — clean
  • cargo t -p signet-rpc-storage — 33 tests pass
  • cargo doc -p signet-rpc-storage — docs build successfully

🤖 Generated with Claude Code

@prestwich prestwich requested a review from a team as a code owner February 11, 2026 21:36
@prestwich prestwich changed the title feat: add signet-rpc-storage crate scaffolding feat: add signet-rpc-storage crate with ETH RPC endpoints Feb 12, 2026
@prestwich
Copy link
Member Author

[Claude Code]

Review Summary

What's here

  • 24 ETH JSON-RPC endpoints (22 supported + 23 explicitly unsupported)
  • Clean crate structure: ctx, resolve, eth/{endpoints, helpers, error, mod}
  • 23 integration tests covering all supported endpoints except eth_call and eth_estimateGas
  • No TODOs, no todo!(), no unimplemented!(), no naked unwrap() in production code
  • Clippy clean on both --all-features and --no-default-features

Issues flagged (inline comments)

Severity Location Issue
High endpoints.rs:647-651 sendRawTransaction fire-and-forget — forwarding errors silently discarded
Medium endpoints.rs:720-722 getLogs range validation — reversed from > to silently accepted
Low helpers.rs:274-276 unreachable!() in build_receipt_envelope — future alloy TxType variants will panic
Info tests/eth_rpc.rs eth_call and eth_estimateGas not yet tested (EVM state setup needed)

Codebase health

  • Zero TODO/FIXME comments
  • Zero panic!/unwrap in non-test code
  • Consistent error handling pattern (.map_err(|e| e.to_string()))
  • Good use of tokio::try_join! for concurrent cold storage reads
  • Tracing spans on EVM execution paths (eth_call, eth_estimateGas)

prestwich and others added 5 commits February 12, 2026 07:51
Add the foundational scaffolding for the signet-rpc-storage crate, which
provides an Ethereum JSON-RPC server backed by signet-storage's unified
storage backend, independent of reth's FullNodeComponents.

This includes:
- Workspace dependency additions (signet-storage, signet-cold, signet-hot,
  signet-storage-types)
- StorageRpcCtx context struct with Arc<Inner> pattern
- BlockTags atomic block tag tracker for Latest/Safe/Finalized
- Block ID and block tag resolution utilities
- Stub eth module (endpoints to be added in follow-up)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement all ETH namespace JSON-RPC endpoints backed by cold/hot storage
instead of reth. Converts eth.rs placeholder into eth/ directory module
with error types, helpers, and 24 supported endpoint handlers:

- Simple queries: blockNumber, chainId
- Block queries: getBlockByHash/Number, getBlockReceipts, headers
- Transaction queries: getTransactionByHash, getTransactionReceipt, raw txs
- Account state (hot storage): getBalance, getStorageAt, getCode, getTransactionCount
- EVM execution: call, estimateGas (via signet-evm/trevm)
- Transaction submission: sendRawTransaction (via TxCache)
- Logs: getLogs with bloom filter matching

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add 23 integration tests covering all endpoint categories: simple
queries, block/transaction lookups, account state, logs, and error
cases. Tests exercise the router through the axum service layer using
tower's oneshot().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- send_raw_transaction: log warning on forwarding failure instead of
  silently discarding the error
- get_logs: reject reversed block ranges (from > to) with an explicit
  error instead of silently returning empty results
- build_receipt_envelope: remove catch-all arm so new TxType variants
  from alloy produce a compile error instead of a runtime panic

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Regular txs execute before system txs, not the other way around.

Drive-by from #74 (comment)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@prestwich prestwich force-pushed the feat/rpc-storage-scaffolding branch from 4341320 to 601c156 Compare February 12, 2026 12:51
prestwich and others added 3 commits February 12, 2026 08:07
- Extract `resolve_evm_block` method on `StorageRpcCtx` to deduplicate
  the block resolution + header fetch + revm db creation shared by
  `call()` and `estimate_gas()`. Resolves headers directly (by hash or
  by tag→number) to avoid redundant cold storage lookups.
- Replace glob import `use endpoints::*` with explicit imports.
- Remove unused `revm_state()` method from `StorageRpcCtx`.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ounds

- Move `resolve_block_id` and `resolve_block_number_or_tag` from free
  functions in resolve.rs to `resolve_block_id` and `resolve_block_tag`
  methods on `StorageRpcCtx`. This eliminates repeated `ctx.tags()` and
  `ctx.cold()` threading at every call site.
- `resolve_block_tag` returns `u64` directly (infallible) instead of
  `Result`, simplifying callers like `get_logs`.
- Remove `H::RoTx: Send + Sync + 'static` bounds from all endpoint
  functions, router, and ctx methods — the trait already provides these.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the bare `rpc_gas_cap` constructor parameter with a
`StorageRpcConfig` struct that bundles all RPC configuration.
This moves `max_blocks_per_filter` from a hard-coded constant to
a configurable value, adds `max_logs_per_response` enforcement
in `eth_getLogs`, and pre-creates a tracing semaphore for future
debug endpoint concurrency limiting.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
prestwich and others added 8 commits February 12, 2026 09:59
Add gas oracle, filters, subscriptions, debug tracing, and signet
namespaces to signet-rpc-storage. Port 15 endpoints from the old
reth-backed signet-rpc crate to the storage-backed architecture.

New modules:
- gas_oracle: cold-storage gas price oracle (suggest_tip_cap)
- interest/: filter manager, subscription manager, block notifications
- debug/: traceBlockByNumber, traceBlockByHash, traceTransaction
- signet/: sendOrder, callBundle

Wired eth endpoints: gasPrice, maxPriorityFeePerGas, feeHistory,
newFilter, newBlockFilter, uninstallFilter, getFilterChanges,
getFilterLogs, subscribe, unsubscribe.

Integration tests cover gas/fee queries, filter lifecycle, and
debug tracing with noop tracer.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use `SealedHeader` with `.hash()` / `.into_inner()` instead of
  `header.hash_slow()`
- Use `RecoveredTx` (pre-recovered sender) instead of manual
  `recover_sender` calls
- Use `ColdReceipt` with per-tx `gas_used` instead of computing
  deltas from cumulative gas
- Delegate `get_logs` to cold storage instead of manual bloom
  filtering and block iteration
- Remove `BlockRangeInclusiveIter`, `collect_matching_logs`,
  `build_receipt_from_parts`, and `recover_sender` helpers
- Simplify `build_rpc_transaction` and `build_receipt` to be
  infallible

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Addresses PR review feedback:
- resolve_block_id now uses hot HotDbRead::get_header_number instead of
  cold storage, making it synchronous and avoiding async overhead
- Add resolve_header for direct header fetches from hot storage,
  eliminating the double header lookup in header_by
- Change not_supported() to return method_not_found() (JSON-RPC -32601)
  instead of internal_error (-32603)
- Update ResolveError to use Storage/Db variants instead of Cold
- Update tests to write headers to both hot and cold storage

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Swap return types to use RpcBlock/RpcReceipt/RpcTransaction/RpcHeader
type aliases, rename tx_by_block_and_index to match rpc naming, fix
not_supported error message, and split call into run_call + call.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Align rpc-storage behavioral semantics with the rpc crate:
- subscribe: require filter for Logs, reject filter for NewHeads via TryFrom impl
- send_raw_transaction: return Result from spawned task instead of swallowing errors
- uninstall_filter/unsubscribe: add HandlerCtx and wrap in spawn_blocking

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…to 0.5

resolve_evm_block previously mapped Pending to Latest without modifying
the header, causing eth_estimateGas (which defaults to Pending) and
eth_call with explicit Pending to see wrong block.number, timestamp,
and base_fee. Now synthesizes a next-block header matching signet-rpc's
block_cfg() behavior.

Also refactors callBundle to use resolve_evm_block instead of duplicating
the pending header logic inline, and passes max_logs to cold.get_logs()
for early termination (signet-cold 0.5 API).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Member Author

@prestwich prestwich left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are there ways that we can DRY endpoint logic or definitions?

prestwich and others added 2 commits February 16, 2026 07:32
* refactor: rewrite block processor to use signet-hot storage

Replace the reth ProviderFactory-based storage with HotKv for rollup
state reads. The processor becomes a stateless executor that reads from
hot storage, runs the EVM, and returns ExecutedBlock. Extraction is
moved to the node (PR3) to avoid lifetime issues with borrowed Extracts.

- Replace Db: NodeTypesDbTrait generic with H: HotKv
- Replace state_provider_database() with revm_state() using RevmRead
- Remove on_host_commit() and commit_evm_results()
- Add process_block() returning ExecutedBlock
- Add build_executed_block() for type conversion
- Remove signet-db, signet-node-types, reth-exex, reth-node-api deps
- Add signet-hot, signet-storage-types deps
- Remove Chain/PrimitivesOf/ExExNotification type aliases from lib.rs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: rewrite signet-node to use unified storage and rpc-storage

Replace reth's ProviderFactory/BlockchainProvider with UnifiedStorage
and swap signet-rpc for signet-rpc-storage. The node now holds
Arc<UnifiedStorage<H>> and shares state with the RPC context through
BlockTags (atomic block tag tracking) and broadcast::Sender
(new block notifications).

Key changes:
- StorageRpcCtx accepts Arc<UnifiedStorage<H>> for shared ownership
- Node struct uses HotKv generic instead of NodeTypesDbTrait
- Block processing uses signet-extract's Extractor + ExtractableChainShim
- Genesis loading via HistoryWrite::load_genesis + UnsafeDbWrite::commit
- Fix metrics bug: record_notification_received now correctly increments
  the received counter instead of the processed counter

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: rewrite node-tests to use unified storage and align gas oracle

Replace TmpDb/ProviderFactory with MemKv/UnifiedStorage in all node test
infrastructure. Update signet-storage crates to v0.6.2 to fix MemKv
intra-transaction read visibility.

Align the cold-storage gas oracle with reth's GasPriceOracle by adding
default_gas_price (1 Gwei), ignore_price (2 wei), and max_price (500
Gwei) to StorageRpcConfig.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: delete signet-db, signet-node-types, and signet-rpc

These crates are fully replaced by signet-storage, signet-hot, and
signet-rpc-storage respectively. Remove 6,700+ lines of dead code and
clean up 22 unused workspace dependencies.

Replace reth-db tempdir_path with tempfile in signet-node-config.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: rename signet-rpc-storage to signet-rpc

Reclaim the signet-rpc name now that the old reth-backed crate is
deleted. Rename directory, package, and all import paths.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: restore RUN EVM ascii art banner

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: resolve clippy empty_line_after_doc_comments warning in ascii banner

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address PR review — bugs, style, and test infra

- Fix log_index per-receipt → per-block (kind.rs)
- Fix hash/height mismatch in update_highest_processed_height (node.rs)
- Fix serve_ipc panic: expect → ? (serve.rs)
- Use seal_unchecked to avoid redundant header re-hashing (processor.rs)
- Refactor imperative event loop → functional chain (processor.rs)
- Add #[instrument(skip_all)] to run_evm and build_executed_block
- Add TODO for two-reader consistency risk (processor.rs)
- Group signet_hot imports across 6 RPC files
- Move supported methods above "Unsupported" comment (eth/mod.rs)
- Hoist function-scoped imports to module level (eth_rpc.rs)
- Fix stale signet_rpc_storage reference (eth_rpc.rs)
- Differentiate HTTP/WS doc comments, fix Result type (serve.rs)
- Wrap cold storage polling loop in 30s timeout (context.rs)
- Remove dead signet_events_in_range method (context.rs)
- Update README to reflect new API types

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Remove `not_supported` pattern; unregistered methods return
  `method_not_found` by default in ajj (threads 14, 15)
- Simplify `SubscriptionNotification`: hardcode `jsonrpc`/`method` in
  manual `Serialize` impl instead of storing as fields (threads 18, 19)
- Change `send_order` return type to `ResponsePayload<(), SignetError>`
  and add fire-and-forget doc comment (threads 5, 7)
- Use `ctx.resolve_header()` (hot storage) instead of
  `cold.get_header_by_number()` in debug endpoints (threads 12, 13)
- Replace `DebugError::Cold(String)` / `Hot(String)` with concrete
  `#[from]` error types; remove `Clone` derive and `into_string`
  (thread 10)
- Parallelize gas oracle transaction reads with `JoinSet` (thread 21)
- Add `tokio-stream` and `tokio-util` to workspace deps (thread 22)
- Add blob gas vec compatibility comment (thread 23)
- Add `State<Db>` / `DatabaseCommit` documentation (thread 20)
- Update README with namespace overview and unsupported methods (thread 16)
- Add blank lines in lib.rs between module groups (thread 2)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
prestwich and others added 2 commits February 16, 2026 10:17
… Paris

`EthereumHardfork` is a bitflags type where each hardfork is an
independent bit. All callers of `load_genesis()` were passing only
`EthereumHardfork::Paris`, so `genesis_header()` never set
`base_fee_per_gas` (a London feature) because the London bit was unset.
The test context worked around this by patching the header after the
fact.

This adds `genesis_hardforks()` to signet-genesis, which derives the
correct set of active hardfork flags by inspecting the chain config's
activation blocks and timestamps. Per-network LazyLock statics and a
`GenesisSpec::genesis_hardforks()` method are also provided. The
workaround in the test context is removed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… PairedHeights

- Unify BlockTags + notification sender into ChainNotifier shared struct
- Replace log-only cold_lag check with proper storage reconciliation
  (unwind to min of hot/cold tips on startup)
- Fix PairedHeights 0/0 fallback to use genesis heights with let-else
- Remove TODO about reader snapshots and redundant map_err
- Replace fully-qualified HotDbRead/HistoryRead syntax with method calls

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The builder previously only loaded genesis into hot storage. Cold-backed
RPC queries for block 0 would fail. Now prebuild checks cold
independently and writes the genesis block if absent.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Member Author

@prestwich prestwich left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how is the storage backend configured in node config?

… merge gas cache

- Bump signet-sdk crates from 0.16.0-rc.8 to 0.16.0-rc.11
- Migrate to new block primitives (Sealed<Header>, SealedBlock<T>)
- Replace ChainSpec with EthereumHardfork bitflags in block processor
- Restructure processor to be instantiated per-block instead of held
- Merge build_executed_block into run_evm, change map_err to wrap_err
- Fix changed flag: on_host_revert/process_committed_chain return bool
- DRY reader/last_block/drop pattern into last_rollup_block() helper
- Remove blank line between imports in gas_oracle.rs
- Merge PR #80: add lock-free GasOracleCache for tip suggestions

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Comment on lines +29 to +31
block: AtomicU64,
/// Cached tip value.
tip: AtomicU64,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having these fields as two separate atomics means there's a slight window for a race. I'm not sure if it's worth worrying about though, given how small the window is, and (I think) the repercussions are likely insignificant.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think the race is fine here. not too concerned about it. same with the race in updating the block tags

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code]

Agreed the race is benign — worst case a reader gets a stale tip value for one request, which is already acceptable since gas prices are advisory. An AtomicU128 packing both fields would close the window, but adds complexity for no practical benefit. Leaving as-is seems right.

prestwich and others added 3 commits February 16, 2026 21:30
…C config

Fix EVM spec_id for RPC calls: all EVM execution paths (eth_call,
eth_estimateGas, eth_createAccessList, debug tracing, bundle simulation)
now derive the correct SpecId from chain config + block header instead of
defaulting to PRAGUE.

Move serve.rs from signet-node to signet-rpc: transport infrastructure
(HTTP/WS/IPC) is now reth-free, using tokio::spawn and Handle::current()
instead of reth's TaskExecutor. This removes axum, tower-http, interprocess,
and ajj dependencies from signet-node.

Load StorageRpcConfig from host RpcServerArgs: rpc_gas_cap,
max_tracing_requests, and gas price oracle settings now flow through from
reth's CLI args instead of always using defaults.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix misleading doc on resolve_evm_block: state is loaded at latest,
  not finalized
- Fix off-by-one in getLogs block range check: inclusive range of
  from..=to spans to-from+1 blocks, so check >= not >
- Remove incorrect override of pending block gas_limit with rpc_gas_cap;
  the parent header's gas_limit (inherited via into_inner) is correct

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
prestwich and others added 2 commits February 17, 2026 11:31
- Fix off-by-one in calculate_reward_percentiles that could skip the
  last transaction or panic on index out of bounds
- Remove unused parent_header SealedHeader conversion in block processor
- Use spawn_with_ctx (async) instead of spawn_blocking_with_ctx for
  send_order which only does async work
- Add clarifying comment on per-block hardfork construction in node

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… code

Bump signet-storage ecosystem deps (storage, cold, hot, types) from
0.6.2 to 0.6.4 and add signet-hot-mdbx / signet-cold-mdbx workspace
deps. Introduce StorageConfig in signet-node-config with FromEnv
derive and a build_storage() method that opens hot+cold MDBX backends
and returns UnifiedStorage<DatabaseEnv>. Replace the old database_path
field and remove dead RocksDB helpers (database_path_str, rocksdb_path,
open_rocks_db).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
prestwich added a commit that referenced this pull request Feb 17, 2026
- Remove `not_supported` pattern; unregistered methods return
  `method_not_found` by default in ajj (threads 14, 15)
- Simplify `SubscriptionNotification`: hardcode `jsonrpc`/`method` in
  manual `Serialize` impl instead of storing as fields (threads 18, 19)
- Change `send_order` return type to `ResponsePayload<(), SignetError>`
  and add fire-and-forget doc comment (threads 5, 7)
- Use `ctx.resolve_header()` (hot storage) instead of
  `cold.get_header_by_number()` in debug endpoints (threads 12, 13)
- Replace `DebugError::Cold(String)` / `Hot(String)` with concrete
  `#[from]` error types; remove `Clone` derive and `into_string`
  (thread 10)
- Parallelize gas oracle transaction reads with `JoinSet` (thread 21)
- Add `tokio-stream` and `tokio-util` to workspace deps (thread 22)
- Add blob gas vec compatibility comment (thread 23)
- Add `State<Db>` / `DatabaseCommit` documentation (thread 20)
- Update README with namespace overview and unsupported methods (thread 16)
- Add blank lines in lib.rs between module groups (thread 2)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
prestwich added a commit that referenced this pull request Feb 17, 2026
… PairedHeights

- Unify BlockTags + notification sender into ChainNotifier shared struct
- Replace log-only cold_lag check with proper storage reconciliation
  (unwind to min of hot/cold tips on startup)
- Fix PairedHeights 0/0 fallback to use genesis heights with let-else
- Remove TODO about reader snapshots and redundant map_err
- Replace fully-qualified HotDbRead/HistoryRead syntax with method calls

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
prestwich added a commit that referenced this pull request Feb 17, 2026
…C config

Fix EVM spec_id for RPC calls: all EVM execution paths (eth_call,
eth_estimateGas, eth_createAccessList, debug tracing, bundle simulation)
now derive the correct SpecId from chain config + block header instead of
defaulting to PRAGUE.

Move serve.rs from signet-node to signet-rpc: transport infrastructure
(HTTP/WS/IPC) is now reth-free, using tokio::spawn and Handle::current()
instead of reth's TaskExecutor. This removes axum, tower-http, interprocess,
and ajj dependencies from signet-node.

Load StorageRpcConfig from host RpcServerArgs: rpc_gas_cap,
max_tracing_requests, and gas price oracle settings now flow through from
reth's CLI args instead of always using defaults.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@prestwich
Copy link
Member Author

[Claude Code]

Closing this PR — the feat/rpc-storage-scaffolding branch has been promoted to the long-lived develop branch. All 40 commits now live on develop. Future work will be merged into develop via individual PRs, and develop will be merged into main for releases.

@prestwich prestwich closed this Feb 17, 2026
@prestwich prestwich deleted the feat/rpc-storage-scaffolding branch February 17, 2026 19:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants